package org.someone.settlement;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.script.ScriptException;

import org.someone.common.CustomMaths;
import org.someone.common.ListTools;
import org.someone.formular.Calculator;

import java.util.Map.Entry;

public class Settlement_oldversion {
	public static final String SettlementType001 = "001"; 
	public static final String SettlementType002 = "002"; 
	
	public static final String ResultType_Weighted_Sum ="WeightedSum";	//先计算各项单价的加权平均然后加权平均单价和为总单价
	public static final String ResultType_Sum_Weighted ="SumWeighted";	//先计算各项单价的和为各批总单价然后计算加权平均单价
	
	static Map<String,String> propsmap;
	static Map<String,String> roundingmap;
	public String getPriceName(){
		return propsmap.get("PriceName");
	}
	
	public String getDeductionName(){
		return propsmap.get("DeductionName");
	}
	
	public String getMAP_KEY_BATCHCODE(){
		return propsmap.get("MAP_KEY_BATCHCODE");
	}
	
	public String getSUFFIX_TARGET(){
		return propsmap.get("SUFFIX_TARGET");
	}
	
	public String getMAP_KEY_AMOUNT_MONEY(){
		return propsmap.get("MAP_KEY_AMOUNT_MONEY");
	}
	
	public String getMAP_KEY_PRICE(){
		return propsmap.get("MAP_KEY_PRICE");
	}
	
	public String getMAP_KEY_AMOUNT(){
		return propsmap.get("MAP_KEY_AMOUNT");
	}
	
	public String getSUMMARYTYPE(){
		return propsmap.get("SUMMARYTYPE");
	}
	
	public String getMAP_KEY_PRICECODE(){
		return propsmap.get("MAP_KEY_PRICECODE");
	}
	
	public String getMAP_KEY_PRICETYPE(){
		return propsmap.get("MAP_KEY_PRICETYPE");
	}
	
	public String getPriceScale(){
		return roundingmap.get("PriceScale");
	}
	
	public Settlement_oldversion() throws UnsupportedEncodingException, IOException{
//		读取配置文件
		InputStream is = SettlementOp.class
				.getResourceAsStream("definition.properties");
		if (is != null) {
			
			Properties props = new Properties();
			props.load(new InputStreamReader(is,"UTF-8"));
			
			propsmap = new HashMap<String,String>();
		    Iterator<Entry<Object, Object>> itr = props.entrySet().iterator();
		    while (itr.hasNext()) {
		      Entry<Object, Object> e = (Entry<Object, Object>) itr.next();
//		      System.out.println(e);
		      propsmap.put(e.getKey().toString(), e.getValue().toString());
		    }
			is.close();
		}
//		读取小数位配置文件
		is = SettlementOp.class
				.getResourceAsStream("rounding-default.properties");
		if (is != null) {
			
			Properties props = new Properties();
			props.load(new InputStreamReader(is,"UTF-8"));
			
			roundingmap = new HashMap<String,String>();
		    Iterator<Entry<Object, Object>> itr = props.entrySet().iterator();
		    while (itr.hasNext()) {
		      Entry<Object, Object> e = (Entry<Object, Object>) itr.next();
//		      System.out.println(e);
		      roundingmap.put(e.getKey().toString(), e.getValue().toString());
		    }
			is.close();
		}
	}
	
//	private String getConvertField(String oValue){
//		return propsmap.get(oValue);
//	}
//	
//	private String convertDef(String strEval){
//		String value = "";
//		Iterator<Entry<String, String>> itr = propsmap.entrySet().iterator();
//		while (itr.hasNext()) {
//	      Entry<String, String> e = (Entry<String, String>) itr.next();
//	      value = strEval.replaceAll(e.getKey().toString(), e.getValue().toString());
//	    }
//		return value;
//	}
	
	/**
	 * 计算价格
	 * @param rownum			分组行号
	 * @param PriceTermsList	价格条款
	 * @param targetMap			指标值map
	 * @return
	 * @throws Exception
	 */
	private Map<String,String> getPriceMap(String rownum, List<Map<String,String>> PriceTermsList, Map<String,String> targetMap) throws Exception{
		Map<String,String> priceMap = new HashMap<String,String>(); 
		for(int i=0; i< PriceTermsList.size(); i++){	//循环结算价格条款
			Map<String,String> pricerow = 
					PriceTermsList.get(i);
			String groupnum = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_GROUPNUM);
			String code = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
			if(code.indexOf(",")!=-1){
				throw new Exception("结算方案模板价格条款不正确，计价分类为不能包含字符<,>。");
			}
			String eval = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL);
			String formula = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA);
			String formulaparam = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA);
			if(SettlementOp.inArray(groupnum, rownum, false)){	//[分组行号相等或分组行号为空]
				try{
					if(Calculator.judgeCondition(eval, targetMap)){	//符合计价条件
						//List<Map<String,String>> groupBatch = ListTools.cloneListMap(sourcesList);
						//替换公式中指标的符号为正确的值
						formula = SettlementOp.replaceFormula(formula, targetMap);
						if(formulaparam!=null&& !"".equals(formulaparam))
						formula = SettlementOp.replaceFormulaParam(formula, formulaparam);
						//计算更新每批次单价
						double price = Calculator.getCalculatorValue(formula);
						
						price = Double.parseDouble(priceMap.get(code)==null?"0":priceMap.get(code)) + price;
						priceMap.put(code, String.valueOf(price));
					}
				}catch(ScriptException s){
					throw new Exception("计算公式："+eval+" 出错");
				}
			}
		}
		return priceMap;
	}
	
	private List<Map<String,String>> writePriceList(List<Map<String,String>> sourcesList, Map<String,String> priceMap){
		List<Map<String,String>> resultList = new ArrayList<Map<String,String>>();
		Iterator<Entry<String, String>> it = priceMap.entrySet().iterator();
		while(it.hasNext()){
			Entry<String, String> e = (Entry<String, String>)it.next();
			String key = e.getKey();
			String value = e.getValue();
			List<Map<String,String>> tmp = ListTools.cloneListMap(sourcesList);
			for(int i=0; i< tmp.size(); i++){
				Map<String,String> batch = tmp.get(i);
				batch.put(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE, key);
				batch.put(key, value);
			}
			resultList.addAll(tmp);
		}
		return resultList;
	}
	
	
	private void appendListMap(List<Map<String,String>> sourcesList, Map<String,String> addMap, String keySuffix){
		Iterator<Entry<String, String>> it = addMap.entrySet().iterator();
		while(it.hasNext()){
			Entry<String, String> e = (Entry<String, String>)it.next();
			String key = e.getKey() + keySuffix==null?"":keySuffix;
			String value = e.getValue();
			for(int i=0; i< sourcesList.size(); i++){
				Map<String,String> batch = sourcesList.get(i);
				batch.put(key, value);
			}
		}
	}
	
	/**
	 * 
	 * @param conditionList				价格条款list
	 * @param sourcesList				源数据list
	 * @param pricebatch				加权质量批次
	 * @param rownum					分组行号
	 * @param priceMode					结算价格类型（价格/增扣）
	 * @return
	 * @throws NumberFormatException
	 * @throws ScriptException
	 * @throws Exception
	 */
	private List<Map<String,String>> doWeightingPrice(List<Map<String,String>> conditionList, List<Map<String,String>> sourcesList, 
			Map<String,String> pricebatch, String rownum, String priceMode) throws Exception{
		List<Map<String,String>> result = new ArrayList<Map<String,String>>();
		for(int i=0; i< conditionList.size(); i++){	//循环结算价格条款
			Map<String,String> pricerow = 
					conditionList.get(i);
			String groupnum = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_GROUPNUM);
			String code = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
			if(code.indexOf(",")!=-1){
				throw new Exception("结算方案模板价格条款不正确，计价分类为不能包含字符<,>。");
			}
			String eval = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL);
			String formula = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA);
			String formulaparam = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA);
			if(SettlementOp.inArray(groupnum, rownum, false)){	//[分组行号相等或分组行号为空]
				try{
					if(Calculator.judgeCondition(eval, pricebatch)){	//符合计价条件
						List<Map<String,String>> groupBatch = ListTools.cloneListMap(sourcesList);
						//替换公式中指标的符号为正确的值
						formula = SettlementOp.replaceFormula(formula, pricebatch);
						if(formulaparam!=null&& !"".equals(formulaparam))
						formula = SettlementOp.replaceFormulaParam(formula, formulaparam);
						//计算更新每批次单价
						double price = Calculator.getCalculatorValue(formula);
						//将得出的单价写入该组各批次数据中
						for(int j=0; j< groupBatch.size(); j++){
							Map<String,String> batch = groupBatch.get(j);
							price = Double.parseDouble(batch.get(code)==null?"0":batch.get(code)) + price;
							//写入价格
							batch.put(code, String.valueOf(price));
							//写入计价分类
							batch.put(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE, code);
							//写入计算处理的分类（价格/增扣）
							batch.put(SettlementOp.PRICE_MODE_KEY, priceMode);
							//将计算加权后的指标写入批次
							Iterator<Entry<String, String>> it = pricebatch.entrySet().iterator();
							while(it.hasNext()){
								Entry<String, String> e = (Entry<String, String>)it.next();
								batch.put(e.getKey() + getSUFFIX_TARGET(), String.valueOf(e.getValue()) );
							}
						}
						result.addAll(groupBatch);
					}
				}catch(ScriptException s){
					throw new Exception("计算公式："+eval+" 出错");
				}
			}
		}
		return result;
	}
	
	/**
	 * 
	 * @param conditionList					条件list
	 * @param sourcesList					源数据list
	 * @param rownum						分组行号
	 * @param priceMode						结算价格类型（价格/增扣）
	 * @return
	 * @throws NumberFormatException
	 * @throws ScriptException
	 * @throws Exception
	 */
	private List<Map<String,String>> doBatchPrice(List<Map<String,String>> conditionList, List<Map<String,String>> sourcesList, 
			List<String> termKeys, String rownum, String priceMode) throws Exception{
		List<Map<String,String>> sourcestmp = ListTools.cloneListMap(sourcesList);
		List<Map<String,String>> result = new ArrayList<Map<String,String>>();
		for(int i=0; i < sourcestmp.size(); i ++){	//循环组内单批次
			for(int pr=0; pr< conditionList.size(); pr++){	//循环结算价格条款
				Map<String,String> pricerow = conditionList.get(pr);
				String groupnum = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_GROUPNUM);
				String code = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
				if(code.indexOf(",")!=-1){
					throw new Exception("结算方案模板价格条款不正确，计价分类为不能包含字符<,>。");
				}
				String eval = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL);
				String formula = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA);
				String formulaparam = (String)pricerow.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA);
				if(SettlementOp.inArray(groupnum, rownum, false)){	//[分组行号相等或分组行号为空]
					Map<String,String> pricebatch = new HashMap<String,String>();
					pricebatch.putAll(sourcestmp.get(i));
					try{
						if(SettlementOp.judgeCondition(termKeys, eval, pricebatch)){	//符合计价条件
							//替换公式中指标的符号为正确的值
							formula = SettlementOp.replaceFormula(formula, termKeys, pricebatch);
							if(formulaparam!=null&& !"".equals(formulaparam))
							formula = SettlementOp.replaceFormulaParam(formula, formulaparam);
							//计算更新每批次单价
							double price = Calculator.getCalculatorValue(formula);
							//将得出的单价写入批次数据中
							price = Double.parseDouble(pricebatch.get(code)==null?"0":pricebatch.get(code)) + price;
							pricebatch.put(code, String.valueOf(price));
							//写入计价分类
							pricebatch.put(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE, code);
							//写入计算处理的分类（价格/增扣）
							pricebatch.put(SettlementOp.PRICE_MODE_KEY, priceMode);
							//					//将计算加权后的指标写入批次								
							for(int k = 0; k< termKeys.size(); k++){
								String key = termKeys.get(k);
								pricebatch.put(key+getSUFFIX_TARGET(), pricebatch.get(key));
							}
							result.add(pricebatch);
						}

					}catch(ScriptException s){
						throw new Exception("计算公式："+eval+" 出错");
					}
				}
			}
		}
		return result;
	}
	/*
	private void getResultSummary(String summaryKey, List<Map<String,String>> result, List<Map<String,String>> sources, String resultType) throws Exception{
		String conditioneval = SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE+SettlementOp.SIGN_EQUAL+"'"+summaryKey+"'";
		List<Map<String,String>> sourceList = null;
		try{
			sourceList = ListTools.cloneListMap(SettlementOp.extract(conditioneval, sources));
		}catch(ScriptException s){
			throw new Exception("解析公式："+conditioneval+" 出错");
		}
		List<String> keys = new ArrayList<String>();
		//将各种价格写入map，并根据费用项目形成合计价格
		for(int i=0; i< sourceList.size(); i++){
			Map<String,String> m = sourceList.get(i);
			String key = m.get(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
			keys.add(key);
			String value = m.get(key)==null?"0":m.get(key);
			String oldVal = "0";
			String sumPrice = "0";
			int batchIndex = Integer.parseInt(m.get(getMAP_KEY_BATCHCODE()))-1;
			if(result.get(batchIndex) == null){
				result.set(batchIndex, m);
			}else{
				oldVal = result.get(batchIndex).get(key)==null?"0":result.get(batchIndex).get(key);
				sumPrice = result.get(batchIndex).get(summaryKey)==null?"0":result.get(batchIndex).get(summaryKey);
				result.get(batchIndex).putAll(m);
				m = result.get(batchIndex);
			}
			
			m.put(key, String.valueOf(CustomMaths.round(Double.parseDouble(value) + Double.parseDouble(oldVal),2)));
			m.put(summaryKey, String.valueOf(CustomMaths.round(Double.parseDouble(value) + Double.parseDouble(sumPrice),2)));
			
			result.set(batchIndex, m);
		}
		keys = new ArrayList<String>(new HashSet<String>(keys));
		
		if(ResultType_Weighted_Sum.equals(resultType)){
			double sumprice = 0.0;
			for(int i=0; i< keys.size(); i++){
				double price = SettlementOp.getWeightedValue(getMAP_KEY_AMOUNT(), keys.get(i), result, Integer.parseInt(getPriceScale()));
				sumprice += price;
				for(int j=0; j< result.size(); j++){
					Map<String,String> m = result.get(j);
					m.put("price_"+keys.get(i), String.valueOf(price));
				}
			}
			sumprice = CustomMaths.round(sumprice, 2);
			for(int i=0; i< result.size(); i++){
				Map<String,String> m = result.get(i);
				double amount = Double.parseDouble(m.get(getMAP_KEY_AMOUNT()));
				double Amountofcoal = CustomMaths.round(amount * sumprice, 2);
				m.put(getMAP_KEY_PRICE(), String.valueOf(sumprice));
				m.put(getMAP_KEY_AMOUNT_MONEY(), String.valueOf(Amountofcoal));
			}
		}else if(ResultType_Sum_Weighted.equals(resultType)){
			double price = SettlementOp.getWeightedValue(getMAP_KEY_AMOUNT(), summaryKey, result, Integer.parseInt(getPriceScale()));
			for(int i=0; i< result.size(); i++){
				Map<String,String> m = result.get(i);
				double amount = Double.parseDouble(m.get(getMAP_KEY_AMOUNT()));
				double Amountofcoal = CustomMaths.round(amount * price, 2);
				m.put(getMAP_KEY_PRICE(), String.valueOf(price));
				m.put(getMAP_KEY_AMOUNT_MONEY(), String.valueOf(Amountofcoal));
			}
		}
		
	}
	*/
	private void SetQuantityKey(List<Map<String,String>> sourcestmp, String QuantityKey) throws Exception{
		for(int i = 0; i< sourcestmp.size(); i++){
			Map<String,String> m = sourcestmp.get(i);
			List<String> keys = SettlementOp.getConditionKeys(QuantityKey);	//得到结算量公式的keys
			String amount = String.valueOf(Calculator.getCalculatorValue(SettlementOp.replaceFormula(QuantityKey, keys, m))); //计算结算量公式
			m.put(getMAP_KEY_AMOUNT(), amount);	//将结算量赋值在记录集Map里
		}
	}
	
	private void SetGroupKeys(List<Map<String,String>> sourcestmp, List<String> Qualitykeys, String Qualitysuffix) throws Exception{
		for(int i = 0; i< sourcestmp.size(); i++){
			Map<String,String> m = sourcestmp.get(i);
			for(int j = 0; j< Qualitykeys.size(); j++){
				String key = Qualitykeys.get(j);
				String value = m.get(key+Qualitysuffix);
				if(value==null || value.equals("")){
					continue;
				}
				String OrginalUnit = m.get(key+Qualitysuffix+"_dw");
				if(OrginalUnit==null || OrginalUnit.equals("")){
					m.put(key,value);
				}else{
					String converteval = propsmap.get(OrginalUnit.toLowerCase());
					if(converteval==null || "".equals(converteval)){
						throw new Exception("配置错误，未设置单位转换公式。");
					}
					m.put(key, SettlementOp.UnitConvertIgnoreCase(key, converteval,value));
				}
			}
//			//处理结算量
//			List<String> keys = SettlementOp.getConditionKeys(QuantityKey);	//得到结算量公式的keys
//			String amount = String.valueOf(Calculator.getCalculatorValue(SettlementOp.replaceFormula(QuantityKey, keys, m))); //计算结算量公式
//			m.put(getMAP_KEY_AMOUNT(), amount);	//将结算量赋值在记录集Map里
		}
	}
	/*
	private List<String> getAllPriceTermsKeys(SettlementTemplate balanceTemplate){
		List<String> resultkeys = new ArrayList<String>();
		List<String> excludeKeys = new ArrayList<String>();	//公式的key
		for(int i=0 ; i<Calculator.funcArray.length; i++){
			excludeKeys.add(Calculator.funcArray[i]);
		}
		
		for(int i = 0; i< balanceTemplate.getPriceTermsList().size(); i++){
			Map<String,String> m = balanceTemplate.getPriceTermsList().get(i);
			resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL).toLowerCase()));
			resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA).toLowerCase()));
			excludeKeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA).toLowerCase()));
		}
		for(int i = 0; i< balanceTemplate.getDeductionList().size(); i++){
			Map<String,String> m = balanceTemplate.getDeductionList().get(i);
			resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL).toLowerCase()));
			resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA).toLowerCase()));
			excludeKeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA).toLowerCase()));
		}
		if(resultkeys.size()==0) return null;
		resultkeys = new ArrayList<String>(new HashSet<String>(resultkeys));
		resultkeys.removeAll(excludeKeys);
		return resultkeys;
	}
	*/
	private List<String> getPriceTermsKeys(SettlementTemplate balanceTemplate, String rownum){
		List<String> resultkeys = new ArrayList<String>();
		List<String> excludeKeys = new ArrayList<String>();	//公式的key
		for(int i=0 ; i<Calculator.funcArray.length; i++){
			excludeKeys.add(Calculator.funcArray[i]);
		}
		
		for(int i = 0; i< balanceTemplate.getPriceTermsList().size(); i++){
			Map<String,String> m = balanceTemplate.getPriceTermsList().get(i);
			if(rownum.equalsIgnoreCase(m.get(SettlementOp.TMP_TERMS_MAP_KEY_GROUPNUM))){
				resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL).toLowerCase()));
				resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA).toLowerCase()));
				excludeKeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA).toLowerCase()));
			}
		}
		for(int i = 0; i< balanceTemplate.getDeductionList().size(); i++){
			Map<String,String> m = balanceTemplate.getDeductionList().get(i);
			if(rownum.equalsIgnoreCase(m.get(SettlementOp.TMP_TERMS_MAP_KEY_GROUPNUM))){
				resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_EVAL).toLowerCase()));
				resultkeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULA).toLowerCase()));
				excludeKeys.addAll(SettlementOp.getConditionKeys(m.get(SettlementOp.TMP_TERMS_MAP_KEY_FORMULAPARA).toLowerCase()));
			}
		}
		if(resultkeys.size()==0) return null;
		resultkeys = new ArrayList<String>(new HashSet<String>(resultkeys));
		resultkeys.removeAll(excludeKeys);
		return resultkeys;
	}
	
	private void writeBatchsResult(Map<String,String> priceMap, List<Map<String,String>> sources){
		for( int i=0; i<sources.size(); i++){
			Map<String,String> tmp = sources.get(i);
			Iterator<Entry<String, String>> it = priceMap.entrySet().iterator();
			while(it.hasNext()){
				Entry<String, String> e = (Entry<String, String>)it.next();
				if(e.getKey().equals(getMAP_KEY_PRICE())){
					String strAmount = tmp.get(getMAP_KEY_AMOUNT());
					double dbAmount = Double.parseDouble(strAmount);
					String strPrice = e.getValue();
					double dbPrice = Double.parseDouble(strPrice);
					double AmountOfCoal = dbAmount * dbPrice;
					tmp.put(getMAP_KEY_AMOUNT_MONEY(), String.valueOf(AmountOfCoal));
				}
				tmp.put(e.getKey(), e.getValue());
			}
		}
	}
	
	private Map<String,String> countWeightedPrice(String strPriceType, String WeightedKey, List<String> keys, List<Map<String,String>> sources, int PriceScale){
//		循环计价类型，得到各计价类型及总计（先加权后汇总、先汇总后加权）的值计入结果Map
		Map<String,String> priceMap = new HashMap<String,String>();
		double sumprice = 0.0;
		for(int i=0; i< keys.size(); i++){
			String key = keys.get(i);
			double price = SettlementOp.getWeightedValue(WeightedKey, key, sources, PriceScale);
			if(key.equals(strPriceType)){
				priceMap.put("price_WeightedAfterSum_"+key, String.valueOf(price));
			}else{
				priceMap.put("price_"+key, String.valueOf(price));
				sumprice += price;
			}
		}
		sumprice = CustomMaths.round(sumprice, 2);
		priceMap.put("price_SumAfterWeighted_" + strPriceType, String.valueOf(sumprice));
		return priceMap;
	}
	
	private List<String> writeBatchPrice(String strPriceType, List<Map<String,String>> result, List<Map<String,String>> sources) throws Exception{
		List<String> keys = new ArrayList<String>();
		//将各种价格写入map，并根据费用项目形成合计价格
		for(int i=0; i< sources.size(); i++){
			Map<String,String> m = sources.get(i);
			String key = m.get(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
			keys.add(key);
			String value = m.get(key)==null?"0":m.get(key);
			String oldVal = "0";
			String sumPrice = "0";
			int batchIndex = Integer.parseInt(m.get(getMAP_KEY_BATCHCODE()))-1;
			if(result.get(batchIndex) == null){
				result.set(batchIndex, m);
			}else{
				oldVal = result.get(batchIndex).get(key)==null?"0":result.get(batchIndex).get(key);
				sumPrice = result.get(batchIndex).get(strPriceType)==null?"0":result.get(batchIndex).get(strPriceType);
				result.get(batchIndex).putAll(m);
				m = result.get(batchIndex);
			}
			
			m.put(key, String.valueOf(CustomMaths.round(Double.parseDouble(value) + Double.parseDouble(oldVal),2)));
			m.put(strPriceType, String.valueOf(CustomMaths.round(Double.parseDouble(value) + Double.parseDouble(sumPrice),2)));
			
			result.set(batchIndex, m);
		}
		keys.add(strPriceType);
		keys = new ArrayList<String>(new HashSet<String>(keys));
		return keys;
	}
	
	public List<String> getDistinctKeys(List<Map<String,String>> sources, String strkeys){
		List<String> arrkeystmp = new ArrayList<String>();
		String[] strkeyarr = strkeys.split(",");
		for(int i = 0; i < sources.size(); i++){
			Map<String,String> mapSource = sources.get(i);
			String strkey = "";
			for(int j =0; j < strkeyarr.length; j ++){
				strkey += mapSource.get(strkeyarr[j]) +",";
			}
			strkey = strkey.substring(0, strkey.length()-1);
			arrkeystmp.add(strkey);			
		}
		List<String> arrkeys = new ArrayList<String>(new HashSet<String>(arrkeystmp));
		return arrkeys;
	}
	
	private List<Map<String,String>> countPriceCode(List<Map<String,String>> sources) throws Exception{
		List<Map<String,String>> result = new ArrayList<Map<String,String>>();
		List<String> listPriceCode = getDistinctKeys(sources, SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
		for(int i=0; i < listPriceCode.size(); i++){
			String strPriceCode = listPriceCode.get(i);
			String strEval = SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE + SettlementOp.SIGN_EQUAL + "'" + strPriceCode + "'";
			List<Map<String,String>> sourceList = null;
			try{
				sourceList = ListTools.cloneListMap(SettlementOp.extract(strEval, sources));
			}catch(ScriptException s){
				throw new Exception("解析公式："+strEval+" 出错");
			}
			String strPrice = String.valueOf(SettlementOp.getWeightedValue(getMAP_KEY_AMOUNT(), strPriceCode, sourceList, Integer.parseInt(getPriceScale())));
			for(int j=0; j< sourceList.size(); j++){
				Map<String,String> m = sourceList.get(j);
				String strAmount = m.get(getMAP_KEY_AMOUNT());
				double dbAmount = Double.parseDouble(strAmount);
				double dbPrice = Double.parseDouble(strPrice);
				double dbAmountOfMoney = CustomMaths.round(dbAmount * dbPrice,2);
				m.put(getMAP_KEY_PRICE(), strPrice);
				m.put(getMAP_KEY_AMOUNT_MONEY(), String.valueOf(dbAmountOfMoney));
			}
			result.addAll(sourceList);
		}
		return result;
	}
	
	private Map<String,String> getSettlTarget(List<Map<String,String>> groupBatch, List<String> termsKeys, String Qualitysuffix) throws Exception{
		//得到特殊处理的MAP
		Map<String,String> mpkeyop = new HashMap<String,String>();
		Map<String,String> mpeval = new HashMap<String,String>();
		if("on".equalsIgnoreCase(propsmap.get("Special_switch"))){
			String strkeys = propsmap.get("Special_KEYS");
			String strkeyop = propsmap.get("Special_KEYOP");
			String streval = propsmap.get("Special_EVAL");
			String [] keyarr = strkeys.split("#");
			String [] keyoparr = strkeyop.split("#");
			String [] evalarr = streval.split("#");
			if(keyarr.length != evalarr.length || keyarr.length != keyoparr.length){
				throw new Exception("配置文件中关于结算指标特殊处理的配置项有误。");
			}
			for(int s=0; s< keyarr.length; s++){
				String key = keyarr[s];
				String op = keyoparr[s];
				String eval = evalarr[s];
				mpkeyop.put(key, op);
				mpeval.put(key, eval);
			}
		}
		
		//构建计算加权指标的List
		List<Map<String,String>> targetList = new ArrayList<Map<String,String>>();
		for(int i=0; i< groupBatch.size(); i++){
			Map<String,String> mpTmp = groupBatch.get(i);		//原listmap
			Map<String,String> mpTarget = new HashMap<String,String>();		//新map
			String weight = mpTmp.get(getMAP_KEY_AMOUNT());
			mpTarget.put(getMAP_KEY_AMOUNT(), weight);
			//循环指标并进行赋值
			for(int k=0; k< termsKeys.size(); k++){
				String key = termsKeys.get(k);
				String value = mpTmp.get(key);
				String op = mpkeyop.get(key);
				if(op != null){
					String strValue = mpTmp.get(key + Qualitysuffix);
					op = op.replaceAll(key, strValue);
					double dbvalue = Calculator.getCalculatorValue(op);
					value = String.valueOf(dbvalue);
				}
				mpTarget.put(key, value);
			}
			targetList.add(mpTarget);
		}
		//循环指标得到加权结果
		Map<String,String> pricebatch = new HashMap<String,String>();
		for(int k=0; k< termsKeys.size(); k++){
			String key = termsKeys.get(k);
			double dbValue = SettlementOp.getWeightedValue(getMAP_KEY_AMOUNT(), key, targetList, 10);
			String eval = mpeval.get(key);
			if(eval != null){
				eval = eval.replaceAll(key, String.valueOf(dbValue));
				dbValue = Calculator.getCalculatorValue(eval);
			}
			pricebatch.put(key, String.valueOf(dbValue));
		}
		
		return pricebatch;
	}
	
	public List<Map<String,String>> Calculation4Details(List<Map<String,String>> sources,SettlementTemplate balanceTemplate) throws Exception{
		if(sources == null || sources.isEmpty()){
			throw new Exception("结算数据为空");
		}
		if(balanceTemplate == null){
			throw new Exception("结算方案模板为空");
		}
//		定义变量
		List<Map<String,String>> details = new ArrayList<Map<String,String>>();	//计算结果
		List<Map<String,String>> sourcestmp = sources;	//得到结算数据
		
//		设置批次自动编码
		for(int i=0; i< sourcestmp.size(); i++){
			Map<String,String> m = sourcestmp.get(i);
			m.put(getMAP_KEY_BATCHCODE(), String.valueOf(i+1));
		}
		List<Map<String,String>> sourcesgroup = ListTools.cloneListMap(sourcestmp);
		
//		获得需要汇总而不是加权平均的指标代码
		String strsumkey = propsmap.get("SUMKEY");
//		获得价格公式中使用的指标Key
//		List<String> termsKeys = getAllPriceTermsKeys(balanceTemplate);
//		if(termsKeys == null){
//			throw new Exception("结算方案模板不正确，结算条款中无可用的结算指标。");
//		}
		
//		解析分组表达式中的变量
		
//		循环分组表达式
		for(int gr=0; gr< balanceTemplate.getGroupList().size(); gr++){
//			List<Map<String,String>> sourcesgroup = ListTools.cloneListMap(sourcestmp);
			Map<String,String> grouprow = balanceTemplate.getGroupList().get(gr);
			String rownum = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_ROWNUM);
			String gEval = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_EVAL);
			String gEval4p = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_EVAL4PRICE);
			String gMode = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_MODE);
			String priceType = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE);	//费用类型
			String QuantityKey = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_Quantity);	//数量结算依据指标代码
			//QuantityKey = propsmap.get(QuantityKey)==null?QuantityKey:propsmap.get(QuantityKey);
			String QualityKey = (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_Quality);	//质量结算依据指标代码
//			异常判断
			if(QuantityKey==null || "".equals(QuantityKey)){
				throw new Exception("结算方案模板分组不正确，数量结算依据指标代码为空。");
			}
			if(QualityKey==null || "".equals(QualityKey)){
				throw new Exception("结算方案模板分组不正确，质量结算依据指标代码为空。");
			}
			if(priceType==null || "".equals(priceType)){
				throw new Exception("结算方案模板分组不正确，费用类型为空。");
			}
			if(priceType.indexOf(",")!=-1){
				throw new Exception("结算方案模板分组不正确，费用类型为不能包含字符<,>。");
			}
			if(gMode==null || "".equals(gMode)){
				throw new Exception("结算方案模板分组不正确，结算模式为空。");
			}
			if(rownum==null || "".equals(rownum)){
				throw new Exception("结算方案模板分组不正确，分组行号为空。");
			}
			if(gEval==null || "".equals(gEval)){
				throw new Exception("结算方案模板分组不正确，分组表达式为空。");
			}
			
			if(gEval4p == null || "".equals(gEval4p)){
				gEval4p = gEval;
			}
			
			QualityKey = propsmap.get(QualityKey)==null?QualityKey:propsmap.get(QualityKey);
			String Qualitysuffix = QualityKey;
			if(Qualitysuffix==null){
				throw new Exception("结算模块配置不正确，未设置结算质量数据后缀。");
			}
//			设置分组后的结算数量
			SetQuantityKey(sourcesgroup, QuantityKey);
//			取得该分组条件的对应指标Key
			List<String> groupKeys = SettlementOp.getConditionKeys(gEval);
//			排除当前数据源中有的,不需要使用厂方、矿方判定的Key
			for(int i=0; i< groupKeys.size(); i++){
				String key = groupKeys.get(i);
				if(sourcesgroup.get(0).get(key) != null){
					groupKeys.remove(key);
				}
			}
//			获得价格公式中使用的指标Key,为了防止加权单批次同时存在时对结算化验指标的输出错误，故需要在每个分组中进行价格指标key 的获取
			List<String> termsKeys = getPriceTermsKeys(balanceTemplate,rownum);
			if(termsKeys == null){
				throw new Exception("结算方案模板不正确，结算条款中无可用的结算指标。");
			}
//			获得需要汇总的数量key
			List<String> sumtermsKeys = new ArrayList<String>();
			for(int i=0; i< termsKeys.size(); i++){
				String key = termsKeys.get(i);
				boolean isSumKey = SettlementOp.inArray(strsumkey, key, true);
				if(isSumKey){
					sumtermsKeys.add(key);
					termsKeys.remove(i--);
				}
			}
//			结算质量指标Keys
			List<String> Keys = new ArrayList<String>();
			Keys.addAll(groupKeys);
			Keys.addAll(termsKeys);
			Keys = new ArrayList<String>(new HashSet<String>(Keys));
//			设置结算质量指标
			SetGroupKeys(sourcesgroup, Keys, Qualitysuffix);
//			得到分组对应批
			List<Map<String,String>> groupBatch;
			if(gEval==null || "".equals(gEval)){	//如果表达式为空默认所有批一个分组
				groupBatch = ListTools.cloneListMap(sourcesgroup);
			}else{
				try{
					groupBatch = ListTools.cloneListMap(SettlementOp.extract(gEval, sourcesgroup));
				}catch(ScriptException s){
					throw new Exception("解析公式："+gEval+" 出错");
				}
			}
//			价格分组批
			List<Map<String,String>> groupBatch4Price;
			if(gEval4p==null || "".equals(gEval4p)){	//如果表达式为空默认所有批一个分组
				groupBatch4Price = ListTools.cloneListMap(sourcesgroup);
			}else{
				try{
					groupBatch4Price = ListTools.cloneListMap(SettlementOp.extract(gEval4p, sourcesgroup));
				}catch(ScriptException s){
					throw new Exception("解析公式："+gEval+" 出错");
				}
			}
//			如果分组批没有数据则计算下一分组条件
			if(groupBatch==null || groupBatch.size()==0 || groupBatch4Price ==null || groupBatch4Price.size()==0){
				continue;
			}
	
//			将组内的费用分类、数量依据、质量依据计入基础数据
			for(int i=0;i< groupBatch4Price.size(); i++){
				Map<String,String> sm = groupBatch4Price.get(i);
				sm.put(SettlementOp.TMP_GROUP_MAP_KEY_ROWNUM, rownum);
				sm.put(SettlementOp.TMP_GROUP_MAP_KEY_MODE, gMode);
				sm.put(SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE, priceType);
				sm.put(SettlementOp.TMP_GROUP_MAP_KEY_Quantity, (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_Quantity));
				sm.put(SettlementOp.TMP_GROUP_MAP_KEY_Quality, (String)grouprow.get(SettlementOp.TMP_GROUP_MAP_KEY_Quality));
			}
			
			//计算价格得到结果
			if(SettlementOp.PRICE_MODE_WEIGHTING.equals(gMode)){	//计价方式加权
				//得到加权后的结算指标
				Map<String,String> pricebatch = getSettlTarget(groupBatch, termsKeys, Qualitysuffix); //
				//数量汇总
				for(int i=0; i< sumtermsKeys.size(); i++){
					String sumKey = sumtermsKeys.get(i);
					double sumValue = SettlementOp.getSumValue(sumKey, groupBatch, 2);
					pricebatch.put(sumKey, String.valueOf(sumValue));
				}
				//指标增扣
				
				//数量增扣
				
				//写入计价指标
				
				
				//处理价格
				if(balanceTemplate.getPriceTermsList().size()>0)
					details.addAll(doWeightingPrice(balanceTemplate.getPriceTermsList(), groupBatch4Price, pricebatch, rownum, getPriceName()));
				//处理增扣
//				if(balanceTemplate.getDeductionList().size()>0)
//					bisic.addAll(doWeightingPrice(balanceTemplate.getDeductionList(), groupBatch, pricebatch, rownum, getDeductionName()));
			}else{												//计价方式单批次
				//处理价格
				if(balanceTemplate.getPriceTermsList().size()>0)
					details.addAll(doBatchPrice(balanceTemplate.getPriceTermsList(), groupBatch4Price, termsKeys, rownum, getPriceName()));
				//处理增扣
//				if(balanceTemplate.getDeductionList().size()>0)
//					bisic.addAll(doBatchPrice(balanceTemplate.getDeductionList(), groupBatch, termsKeys, rownum, getDeductionName()));
			}
		}
		
		if(details.isEmpty()){
			throw new Exception("依据当前的结算条件及数据，无法结算。");
		}
		return details;
	}
	
	public List<Map<String,String>> Calculation4Totals(List<Map<String,String>> details) throws Exception{
//		提取分组规则，得到结算分组结果的分组项。
		List<Map<String,String>> totals = new ArrayList<Map<String,String>>();
		List<String> groupArr = getDistinctKeys(details, SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE+","+SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE);
//		循环分组项得到相应的单价及分类
		for(int i =0; i < groupArr.size(); i++){
			String strGroupEval = groupArr.get(i);
			String[] arrEval = strGroupEval.split(",");
			if(arrEval == null || arrEval.length!=2){
				continue;
			}
			Map<String,String> total = new HashMap<String,String>();
			String strEval = SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE + SettlementOp.SIGN_EQUAL + "'" + arrEval[0] + "'&&" + SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE + SettlementOp.SIGN_EQUAL +"'" + arrEval[1] + "'";
			List<Map<String,String>> arrBatch = ListTools.cloneListMap(SettlementOp.extract(strEval, details));
			double amountMoney = 0.0;
//			循环批次计算单批次总金额
			for(int m =0; m< arrBatch.size(); m++){
				Map<String,String> batch = arrBatch.get(m);
				String strprice = batch.get(arrEval[1]);
				String strquantity = batch.get(getMAP_KEY_AMOUNT());
				double dbprice = Double.parseDouble(strprice==null?"0":strprice);
				double dbquantity = Double.parseDouble(strquantity==null?"0":strquantity);
				amountMoney += dbquantity * dbprice;
			}
//			写入分类及金额
			total.put(SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE, arrEval[0]);
			total.put(SettlementOp.TMP_TERMS_MAP_KEY_PRICECODE, arrEval[1]);
			total.put(SettlementOp.MAP_KEY_MONEY, String.valueOf(amountMoney));
			totals.add(total);
		}
		return totals;
	}
	
	public List<Map<String,String>> getResult4Batchs(List<Map<String,String>> sources,List<Map<String,String>> details, String settlementType) throws Exception{
//		构建一个与sources同样长度的定长List
		List<Map<String,String>> template = new ArrayList<Map<String,String>>();
		List<Map<String,String>> batchs = new ArrayList<Map<String,String>>();
		for(int i=0; i< sources.size(); i++){
			template.add(null);
		}
//		提取费用项目，得到结算分组结果的条件
		List<String> groupArr = getDistinctKeys(details, SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE);
//		循环费用项目得到分组对应的批次
		for(int i =0; i < groupArr.size(); i++){
			String strPriceType = groupArr.get(i);
			String strEval = SettlementOp.TMP_GROUP_MAP_KEY_PRICETYPE + SettlementOp.SIGN_EQUAL + "'" + strPriceType + "'";
			List<Map<String,String>> sourceList = null;
			try{
				sourceList = ListTools.cloneListMap(SettlementOp.extract(strEval, details));
			}catch(ScriptException s){
				throw new Exception("解析公式："+strEval+" 出错");
			}
			//如果是需要进行汇总的费用类型
			if(SettlementOp.inArray(getSUMMARYTYPE(), strPriceType, false)){
				List<Map<String,String>> result = ListTools.cloneListMap(template);
//				按照批次统计各批次的计价单价，并将总价写入key值为strPriceType中
				List<String> keys = writeBatchPrice(strPriceType, result, sourceList);
//				将各计价分类的单价加权值写入key值为price_计价分类中
				Map<String,String> priceMap = countWeightedPrice(strPriceType, getMAP_KEY_AMOUNT(), keys, result, Integer.parseInt(getPriceScale()));
//				根据结算类型写入price、Amountofcoal
				String price = "";
				if(SettlementType001.equals(settlementType)){
					price = priceMap.get("price_SumAfterWeighted_" + strPriceType);
				}else if(SettlementType002.equals(settlementType)){
					price = priceMap.get("price_WeightedAfterSum_" + strPriceType);
				}
				priceMap.put(getMAP_KEY_PRICE(), String.valueOf(price));
				writeBatchsResult(priceMap, result);
				
				batchs.addAll(result);
			}else{	//不需要汇总的费用类型
				batchs.addAll(countPriceCode(sourceList));
			}
		}
		return batchs;
	}
	
	public SettlementResult Calculation(List<Map<String,String>> sources,SettlementTemplate balanceTemplate) throws Exception{
//		参数验证
		if(sources == null || sources.isEmpty()){
			throw new Exception("结算数据为空");
		}
		if(balanceTemplate == null){
			throw new Exception("结算方案模板为空");
		}
//		结算结果
		SettlementResult sr = new SettlementResult();
//		计算结算明细结果
		List<Map<String,String>> details = Calculation4Details(sources, balanceTemplate);
		sr.setDetails(details);
//		计算结算汇总结果
		List<Map<String,String>> totals = Calculation4Totals(details);
		sr.setTotals(totals);
		
		return sr;
	}
	
	/**
	 * 
	 * @param sources			结算批数据
	 * @param balanceTemplate	结算方案
	 * @return
	 * @throws Exception
	 */
	public List<Map<String,String>> toBalance(List<Map<String,String>> sources,SettlementTemplate balanceTemplate, String settlementType) throws Exception{
		if(settlementType == null || "".equals(settlementType)){
			throw new Exception("结算类型为空");
		}
		SettlementResult sr = Calculation(sources, balanceTemplate);
		List<Map<String,String>> result = getResult4Batchs(sources, sr.getDetails(), settlementType);
		return result;
	}
}
